home *** CD-ROM | disk | FTP | other *** search
/ Network Support Library / RoseWare - Network Support Library.iso / apidev / netman.arc / READ.ME < prev   
Text File  |  1989-08-22  |  36KB  |  1,181 lines

  1.                             Network Mandelbrot Set
  2.  
  3. This text documents the programs LEADER.PAS and FOLLOWER.PAS are written in
  4. Borland Turbo Pascal version 5.0.  They use standard file locking to enable
  5. distributed processing of the Mandelbrot set over virtually any PC-based LAN. 
  6. The code is presented more as an example of programming and framework for
  7. personal enhancement than it is as a full-featured software package (although
  8. the extension of the user interface and addition of other capabilities could
  9. easily make it one with only a modest programming effort).
  10.  
  11.                           What is the Mandelbrot Set?
  12.  
  13. The Mandelbrot set has been described as "one of the most beautiful objects of
  14. mathematics".  Technically it is a set of points described by iterative
  15. equations.  It is a member of the family of fractals, equations so named
  16. because they describe "fractional" dimensions (rather than linear forms such as
  17. Cartesian functions).
  18.  
  19. There are many excellent sources on this exciting and emerging field of
  20. "chaology" (the study of chaos) of which fractals are only a facet (see Chaos:
  21. Making a New Science by James Gleick, Viking).  Here only a short description
  22. will be presented.  The steps are as follows:
  23.  
  24. 1. Map a computer screen so that every pixel corresponds to a corresponding
  25. real number position on a coordinate plane not larger than 2 units from the
  26. origin in any direction.
  27.  
  28. 2. Repeat the following algorithm for every pixel:
  29.  
  30. 2a. Assign the X value of the point to a variable (say, of the same name), as
  31. with Y.
  32.  
  33. 2b. Initialize two real number variables (say, ZR and ZI) to zero.
  34.  
  35. 2c. Replace ZR with the square of itself subtracted from the square of ZI plus
  36. X, that is
  37.  
  38. ZR -> ZR^2 - ZI^2 + X
  39.  
  40. 2d. Replace ZI with twice ZR multiplied by itself plus Y, that is,
  41.  
  42. ZI -> 2 * ZR * ZI + Y
  43.  
  44. 2e. Repeat the above operations (from 2a) for at most some arbitrary large
  45. number of times consistent for every pixel (say I) or while the square root of
  46. the sum of the squares of ZR and ZI is less than two, that is,
  47.  
  48. sqrt(ZR^2 + ZI^2) < 2
  49.  
  50. 3. Color the corresponding pixels on the screen according to the number of
  51. iterations spent in the loop (say, I') above (2a-2e) per pixel.
  52.  
  53. Now, much underlying mathematical meaning has been removed from the process
  54. described above; it only hints of "linear distance" and "imaginary numbers"
  55. etc., concepts that are not crucial to programming it.  However, the process
  56. certainly seems rather arbitary without this background.
  57.  
  58. By convention, the "color" referred to in step 3 is that which results when I'
  59. is mapped on to the color spectrum with blue for low values and red for high
  60. values.
  61.  
  62. Now, for coordinates where I' = I (that is, the loop does not terminate
  63. prematurely because the condition under 2e is satisfied) are presumed to lie in
  64. the "Mandelbrot Set".  Technically this names those coordinates that NEVER
  65. satisfy the condition but on computers (as not necessarily in mathematics)
  66. infinity is to be avoided, or at least until processors achieve transcendental
  67. computation.
  68.  
  69.                                  The Approach
  70.  
  71. Two programs named LEADER and FOLLOWER are used, analogous to "servers and
  72. clients" or "masters and slaves".  They were written in Turbo 5.0 Pascal
  73. adhering to DOS file-locking standards (provided by the program SHARE).  Here
  74. is the general flow of events:
  75.  
  76.                                   - LEADER -
  77.  
  78. 1. Displays a title screen.
  79.  
  80. 2. Creates a file FRACTAL.DAT that corresponds in size to that of the internal
  81. representation of the screen (for example, a low-resolution CGA mode takes 16K,
  82. so the file is padded to that size).
  83.  
  84. 3. Creates the auxiliary file VALUES.DAT that contains numerical descriptions
  85. of screen dimensions and formats.
  86.  
  87.                                  - FOLLOWER -
  88.  
  89. 4. Meanwhile has been waiting for the cue to start, which is the presence of
  90. the VALUES.DAT file.
  91.  
  92. 4. Springs to life the moment it detects the existence of the auxiliary file
  93. written by the LEADER and saves the data therein to internal memory, and enters
  94. the main loop.
  95.  
  96. 5. (In the main loop) determines and takes the next available (uncomputed)
  97. screen line by interpreting and updating information in VALUES.DAT.
  98.  
  99. 6. Processes the line and sends the raw screen data to the corresponding
  100. position in FRACTAL.DAT.
  101.  
  102. 7. Gives a visual cue as to the overall progress of work and repeats the last
  103. two steps if there is unfinished work.  Otherwise it is the last to finish and
  104. deletes the VALUES.DAT file.
  105.  
  106.                                   - LEADER -
  107.  
  108. 8. Meanwhile has been providing a visual cue of the progress of FOLLOWER(s).
  109.  
  110. 9. Springs to life again from this dormancy as VALUES.DAT vanishes when deleted
  111. by the last FOLLOWER.
  112.  
  113. 10. Displays the results in FRACTAL.DAT and allows the cycle to be repeated for
  114. a new coordinate region.
  115.  
  116. All of this is done in a way that addresses considerations involved with
  117. concurrent file usage and places no upper limit on the number of FOLLOWER
  118. participants whatsoever (of course at least one must exist).
  119.  
  120.                                Notes on Programs
  121.  
  122. These descriptions refer sequentially to the lines in the programs LEADER and
  123. FOLLOWER.
  124.  
  125.                                   - LEADER -
  126.  
  127.   1 {$define WEAVE}
  128.   2 
  129.   3 program Leader;
  130.   4 
  131.   5 uses Drivers, Graph, DOS, CRT;
  132.   6 
  133.   7 const GraphMode = MCGAC0;
  134.   8       GraphDriver = MCGA;
  135.   9       Block = 50;
  136.  10       ScreenMap = $b800;
  137.  11       BitsPerHue = 2;
  138.  12       Threshold = 4;
  139.  13       Path='.';
  140.  14       Painting = 'FRACTAL.DAT';
  141.  15       Framework = 'VALUES.DAT';
  142.  16 
  143.  17 {$ifdef WEAVE}
  144.  18       Interlace = true;
  145.  19       ScreenMap2 = $ba00;
  146.  20       HalfLine = 100;
  147.  21 {$else}
  148.  22       Interlace = false;
  149.  23 {$endif}
  150.  24 
  151.  25 const No_Error = $00;
  152.  26       Not_Found = $02;
  153.  27       Access_Denied = $05;
  154.  28 
  155.  29 const Read_Only = $00;
  156.  30       Write_Only = $01;
  157.  31       Read_Write = $02;
  158.  32       Deny_All = $10;
  159.  33       Deny_Write = $20;
  160.  34       Deny_Read = $30;
  161.  35       Deny_None = $40;
  162.  36 
  163.  37 type Border = (Upper, Lower, Leftmost, Rightmost);
  164.  38      Count_Type = byte;
  165.  39      Size_Type = word;
  166.  40      Real_Type = real;
  167.  41 
  168.  42 var Hues: byte;
  169.  43     Fence: array[Border] of Real_Type;
  170.  44 
  171.  45 procedure Arrive;
  172.  46 
  173.  47 procedure Property;
  174.  48 
  175.  49 var Xasp,
  176.  50     Yasp: word;
  177.  51     Width,
  178.  52     Height: longint;
  179.  53     Adjust: real;
  180.  54 
  181.  55 begin
  182.  56 GetAspectRatio(Xasp, Yasp);
  183.  57 Width:=(GetMaxX + 1) * Xasp;
  184.  58 Height:=(GetMaxY + 1) * Yasp;
  185.  59 if Width > Height
  186.  60 then begin
  187.  61      Adjust:=2 * (Width / Height);
  188.  62      Fence[Upper]:=2;
  189.  63      Fence[Lower]:=-2;
  190.  64      Fence[Leftmost]:=-Adjust;
  191.  65      Fence[Rightmost]:=Adjust;
  192.  66      end
  193.  67 else begin
  194.  68      Adjust:=2 * (Height / Width);
  195.  69      Fence[Upper]:=Adjust;
  196.  70      Fence[Lower]:=-Adjust;
  197.  71      Fence[Leftmost]:=-2;
  198.  72      Fence[Rightmost]:=2;
  199.  73      end;
  200.  74 end;
  201.  75 
  202.  76 var Mode,
  203.  77     Driver,
  204.  78     Result: integer;
  205.  79 
  206.  80 begin
  207.  81 Mode:=GraphMode;
  208.  82 Driver:=GraphDriver;
  209.  83 Result:=RegisterBGIdriver(@CGADriverProc);
  210.  84 InitGraph(Driver, Mode, Path);
  211.  85 Hues:=GetMaxColor + 1;
  212.  86 Property;
  213.  87 end;
  214.  88 
  215.  89 type Shape = record
  216.  90                Sound: boolean;
  217.  91                ForeV,
  218.  92                RearV: Size_Type;
  219.  93 
  220.  94                H,
  221.  95                V: Size_Type;
  222.  96                Most: Count_Type;
  223.  97                BitPixel,
  224.  98                PixelByte: byte;
  225.  99                ByteLine: word;
  226. 100                Top,
  227. 101                Left,
  228. 102                YInc,
  229. 103                XInc: Real_Type;
  230. 104                Weave: boolean;
  231. 105              end;
  232. 106 
  233. 107 var Seed: Shape;
  234. 108     Canvas: file;
  235. 109 
  236. 110 const Outgoing = true;
  237. 111       Incoming = false;
  238. 112 
  239. 113 {$ifdef WEAVE}
  240. 114 
  241. 115 procedure Door(Outgoing: boolean);
  242. 116 
  243. 117 var Size: word;
  244. 118     Screen: pointer;
  245. 119 
  246. 120 begin
  247. 121 Screen:=Ptr(ScreenMap, $0);
  248. 122 with Seed
  249. 123 do begin
  250. 124    Size:=Block * ByteLine;
  251. 125    if Outgoing
  252. 126    then begin
  253. 127         Rewrite(Canvas, ByteLine);
  254. 128         BlockWrite(Canvas, Screen^, HalfLine);
  255. 129         Screen:=Ptr(ScreenMap2, 0);
  256. 130         BlockWrite(Canvas, Screen^, HalfLine);
  257. 131         end
  258. 132    else begin
  259. 133         FileMode:=Read_Only + Deny_None;
  260. 134         Reset(Canvas, ByteLine);
  261. 135         BlockRead(Canvas, Screen^, HalfLine);
  262. 136         Screen:=Ptr(ScreenMap2, 0);
  263. 137         BlockRead(Canvas, Screen^, HalfLine);
  264. 138         end;
  265. 139    end;
  266. 140 Close(Canvas);
  267. 141 end;
  268. 142 
  269. 143 {$else}
  270. 144 
  271. 145 procedure Door(Outgoing: boolean);
  272. 146 
  273. 147 var Size: word;
  274. 148     Lines: Size_Type;
  275. 149     Screen: pointer;
  276. 150 
  277. 151 begin
  278. 152 Screen:=Ptr(ScreenMap, $0);
  279. 153 with Seed
  280. 154 do begin
  281. 155    Size:=Block * ByteLine;
  282. 156    if Outgoing
  283. 157    then Rewrite(Canvas, ByteLine)
  284. 158    else begin
  285. 159         FileMode:=Read_Only + Deny_None;
  286. 160         Reset(Canvas, ByteLine);
  287. 161         end;
  288. 162    Lines:=V1;
  289. 163    repeat
  290. 164      if Outgoing
  291. 165      then BlockWrite(Canvas, Screen^, Block)
  292. 166      else BlockRead(Canvas, Screen^, Block);
  293. 167      Inc(longint(Screen), Size);
  294. 168      Dec(Lines, Block);
  295. 169    until (Lines = 0)
  296. 170    end;
  297. 171 Close(Canvas);
  298. 172 end;
  299. 173 
  300. 174 {$endif}
  301. 175 
  302. 176 procedure Blend;
  303. 177 
  304. 178 begin
  305. 179 end;
  306. 180 
  307. 181 procedure Cultivate;
  308. 182 
  309. 183 const On = true;
  310. 184       Off = false;
  311. 185 
  312. 186 procedure Plant;
  313. 187 
  314. 188 const BitByte = 8;
  315. 189 
  316. 190 var Notice: file of Shape;
  317. 191 
  318. 192 begin
  319. 193 with Seed
  320. 194 do begin
  321. 195    Sound:=Off;
  322. 196    V:=GetMaxY + 1;
  323. 197    ForeV:=V;
  324. 198    RearV:=V;
  325. 199    H:=GetMaxX + 1;
  326. 200    Most:=Threshold;
  327. 201    BitPixel:=BitsPerHue;
  328. 202    PixelByte:=BitByte div BitPixel;
  329. 203    ByteLine:=H div PixelByte;
  330. 204    Top:=Fence[Upper];
  331. 205    Left:=Fence[Leftmost];
  332. 206    YInc:=(Fence[Upper] - Fence[Lower]) / V;
  333. 207    XInc:=(Fence[Rightmost] - Fence[Leftmost]) / H;
  334. 208    Weave:=Interlace;
  335. 209    end;
  336. 210 Assign(Canvas, Painting);
  337. 211 Door(Outgoing);
  338. 212 Assign(Notice, Framework);
  339. 213 Rewrite(Notice);
  340. 214 Write(Notice, Seed);
  341. 215 Close(Notice);
  342. 216 end;
  343. 217 
  344. 218 procedure Grow;
  345. 219 
  346. 220 type Header = record
  347. 221                 Sound: boolean;
  348. 222                 AtV,
  349. 223                 ToV: Size_Type;
  350. 224               end;
  351. 225 
  352. 226 var Eye: file of Header;
  353. 227 
  354. 228 procedure Ready;
  355. 229 
  356. 230 begin
  357. 231 FileMode:= Read_Write + Deny_None;
  358. 232 Assign(Eye, Framework);
  359. 233 end;
  360. 234 
  361. 235 var Line: string;
  362. 236 
  363. 237 function Ripe: boolean;
  364. 238 
  365. 239 var Result: word;
  366. 240     Place: Header;
  367. 241 
  368. 242 begin
  369. 243 {$i-}
  370. 244 Reset(Eye);
  371. 245 {$i+}
  372. 246 Result:=IOResult;
  373. 247 if (Result = No_Error)
  374. 248 then begin
  375. 249      Read(Eye, Place);
  376. 250      Close(Eye);
  377. 251      Str(Place.AtV, Line);
  378. 252      end;
  379. 253 Ripe:=(Result = Not_Found);
  380. 254 end;
  381. 255 
  382. 256 const Time = 500;
  383. 257 
  384. 258 begin
  385. 259 Ready;
  386. 260 Line:='';
  387. 261 repeat
  388. 262   SetColor(White);
  389. 263   OutTextXY(0,0,Line);
  390. 264   Delay(Time);
  391. 265   SetColor(Black);
  392. 266   OutTextXY(0,0,Line);
  393. 267 until Ripe;
  394. 268 end;
  395. 269 
  396. 270 procedure Harvest;
  397. 271 
  398. 272 begin
  399. 273 Door(Incoming);
  400. 274 end;
  401. 275 
  402. 276 begin
  403. 277 Plant;
  404. 278 Grow;
  405. 279 Harvest;
  406. 280 end;
  407. 281 
  408. 282 procedure NewRegion;
  409. 283 
  410. 284 const Step = 4;
  411. 285 
  412. 286 const Scan = #0;
  413. 287       Enter = #13;
  414. 288       Up = #72;
  415. 289       Down = #80;
  416. 290       Left = #75;
  417. 291       Right = #77;
  418. 292       Reduce = #115;
  419. 293       Enlarge = #116;
  420. 294 
  421. 295 var Key: char;
  422. 296     Xasp,
  423. 297     Yasp: word;
  424. 298     X,
  425. 299     Y,
  426. 300     Width,
  427. 301     Height: Size_Type;
  428. 302     Ratio: Real_Type;
  429. 303 
  430. 304 begin
  431. 305 X:=GetMaxX div 2;
  432. 306 Y:=GetMaxY div 2;
  433. 307 Width:=GetMaxX div 2;
  434. 308 Ratio:=Seed.V / Seed.H;
  435. 309 SetWriteMode(XORPut);
  436. 310 SetColor(Random(GetMaxColor) + 1);
  437. 311 repeat
  438. 312   Height:=round(Width * Ratio);
  439. 313   Rectangle(X - Width, Y - Height, X + Width, Y + Height);
  440. 314   Key:=ReadKey;
  441. 315   Rectangle(X - Width, Y - Height, X + Width, Y + Height);
  442. 316   if Key = Scan
  443. 317   then begin
  444. 318        Key:=ReadKey;
  445. 319        case Key
  446. 320        of Up: Dec(Y, Step);
  447. 321           Left: Dec(X, Step);
  448. 322           Right: Inc(X, Step);
  449. 323           Down: Inc(Y, Step);
  450. 324           Reduce: Dec(Width, Step);
  451. 325           Enlarge: Inc(Width, Step);
  452. 326        end;
  453. 327        end;
  454. 328 until Key = Enter;
  455. 329 Fence[Upper]:=Fence[Upper] - Seed.YInc * (Y - Height);
  456. 330 Fence[Lower]:=Fence[Lower] + Seed.YInc * (GetMaxY - Y - Height);
  457. 331 Fence[Leftmost]:=Fence[Leftmost] + Seed.XInc * (X - Width);
  458. 332 Fence[Rightmost]:=Fence[Rightmost] - Seed.XInc * (GetMaxX - X - Width);
  459. 333 end;
  460. 334 
  461. 335 procedure Depart;
  462. 336 
  463. 337 begin
  464. 338 CloseGraph;
  465. 339 end;
  466. 340 
  467. 341 var key:char;
  468. 342 
  469. 343 begin
  470. 344 Arrive;
  471. 345 repeat
  472. 346   Cultivate;
  473. 347   NewRegion;
  474. 348 until false;
  475. 349 Depart;
  476. 350 end.
  477.  
  478.                                    Comments
  479.  
  480. WEAVE:                  symbol that indicates the use of interlacing in
  481.                         graphics mode
  482.  
  483. Untyped constants defined in lines 7 - 23:
  484.  
  485. GraphMode               (TP constant) defines the mode for display
  486. GraphDriver             (TP constant) defines the driver for display
  487. Block                   size of I/O block operations involving the screen; must
  488.                         divide the number of lines in the selected GraphMode
  489. ScreenMap               memory address of the screen
  490. BitsPerHue              the number of bits required to represent all colors in
  491.                         the selected GraphMode
  492. Threshold               the variable I as defined above
  493. Path                    used to locate BGI files in call to InitGraph;
  494.                         necessary only if the link module Drivers is not used
  495. Painting                name of file containing raw graphics data
  496. Framework               name of auxiliary file
  497. Interlace               declared true if WEAVE is defined, false otherwise
  498. ScreenMap2              memory address of second half of interlaced screen
  499.                         (declared only if WEAVE is defined)
  500. HalfLine                the screen line that separates the two interlaced
  501.                         halves of the screen (declared only if WEAVE is
  502.                         defined)
  503.  
  504. Lines 25 - 35 define constants used for TP error codes and specifying DOS file
  505. sharing modes.  The latter are used with the Turbo Pascal variable FileMode
  506. provided expressly for this purpose.  The constants in lines 29 - 31 determine
  507. the access mode (read and/or write).  The other constants in lines 32 - 35
  508. reflect file sharing modes as defined by DOS in version 3.1 and later as
  509. provided by the SHARE program.  They are used both to determine whether a file
  510. is accessable when OPENed and to specify the availability of the file with
  511. external (non-local) access.  The mode remains in effect until the file is
  512. subsequently CLOSEd and is passed to DOS from Pascal only with the Reset call.
  513.  
  514.  
  515. Lines 37 - 40 define types for internal variables:
  516.  
  517. Border                  edges of screen
  518. Count_Type              type of variable to hold I as defined above
  519. Size_Type               type of variable to hold screen dimensions in pixels
  520. Real_Type               type of variable used to do real computations
  521.  
  522. Lines 42 and 43 define two global variables:
  523.  
  524. Hues                    the number of colors in a pixel for GraphMode
  525. Fence                   the borders of the region in use
  526.  
  527. Lines 45 - 74 form the Arrive procedure that activates the graphics mode and
  528. initializes various variables (Hues and Fence).  Fence is adjusted to respect
  529. the screen aspect ratio.  Thus the 2 unit radius circle that confines the
  530. MandelBrot set actually would actually appear as a circle on the screen (not
  531. distorted due to pixel height vs. width variation).
  532.  
  533. Lines 89 through 105 define the Shape record.  The auxiliary file VALUES.DAT
  534. consists of one such record.
  535.  
  536. ForeV                   the next unprocessed line
  537. RearV                   the last processed line
  538. H                       screen width in pixels
  539. V                       screen height in pixels
  540. Most                    threshold as defined above
  541. BitPixel                BitsPerHue as defined above
  542. PixelByte               pixels per byte in GraphMode (equal to 8 divided by
  543.                         BitPixel)
  544. ByteLine                bytes per line in GraphMode (equal to H divided by
  545.                         PixelByte)
  546. Top                     real number value of upper edge of region (equal to
  547.                         Fence[Upper])
  548. Left                    real number value of left edge of region (equal to
  549.                         Fence[Leftmost])
  550. YInc                    corresponding real number size of pixel height
  551. XInc                    corresponding real number size of pixel width
  552. Weave                   equal to Interlace as defined above
  553.  
  554. Lines 107 and 108 declares Seed (the auxiliary data) as a file of Shapes, and
  555. Canvas (the raw graphics data) as an untyped file.
  556.  
  557. Lines 110 and 110 declare the constants Outgoing and Incoming used the
  558. following procedure Door.
  559.  
  560. Door at lines 113 - 174 will compile to one of two sections of code depending
  561. on the WEAVE setting (that is, whether the GraphMode uses interlacing).  Lines
  562. 115 - 141 contain the interlace version and 145 - 172 the non-interlace. 
  563. Basically the routines use BlockRead or BlockWrite to load or save the entire
  564. screen to the graphics file (based on the Ingoing/Outgoing parameter).  The I/O
  565. is separated into blocks of Block lines (defined above).  (Currently the save
  566. routine is used only to pad the graphics file prior to processing but would be
  567. useful for future code that saves images.)
  568.  
  569. Lines 176 - 179 form an empty subroutine designed for future use of defined
  570. color palette settings.
  571.  
  572. Lines 181 - 280 form the Cultivate subroutine which contains the complete
  573. processing cycle:
  574.  
  575. Plant is the name for the first subroutine of the group, lines 186 - 216.  This
  576. sets up the two data files.  Note that the file variable Notice (representing
  577. the auxiliary file) is created and CLOSEd last to signal readiness to followers
  578. (by Turbo definition any file opened with ReWrite is opened in the "Deny All"
  579. mode).
  580.  
  581. The procedure Grow (lines 218 - 268) redefines the header of the auxiliary file
  582. as Header.  This allows it to monitor the variable AtV which reflects the
  583. current state of processing, using the file variable Eye of type Header.  Note
  584. that the file may be inaccessable due to simultaneous access by a FOLLOWER.
  585.  
  586. The function Ripe (lines 237 - 254) determines whether the file is inaccessable
  587. due to a sharing conflict (in which case it resolves to false) or the actual
  588. disappearance of the file (in which case it returns true signifying
  589. completion).  The function also sets the string variable Line with the current
  590. line number so that it can be reported by Grow (line 263).  The Delay at line
  591. 264 is present so that the leader does not jam the network with requests to
  592. merely monitor the file (the file sharing mode conflicts with FOLLOWER use).
  593.  
  594. The procedure Harvest (lines 270 - 274) loads the newly completed image.
  595.  
  596. The procedure NewRegion (lines 282 - 333) allows the user to select a new
  597. region relative to the old in a straightforward way.  Cursor keys change the
  598. location of the window.  The CTRL key paired with the left and right arrows
  599. changes the size of the window.  The Fence variable is updated to reflect the
  600. newly selected region.  Note that the aspect ratio is preserved by the use of
  601. the Ratio variable.
  602.  
  603. Procedure Depart (lines 335 - 339) is designed as the twin of Arrive to handle
  604. proper termination procedure.
  605.  
  606.                                  - FOLLOWER -
  607.  
  608.   1 {$ifdef CPU87}
  609.   2   {$N+}
  610.   3 {$endif}
  611.   4 
  612.   5 program Follower;
  613.   6 
  614.   7 uses Graph, Crt, Drivers, Fonts;
  615.   8 
  616.   9 const Choir = 5;
  617.  10       Bass = 200;
  618.  11       Treble = 1500;
  619.  12       Tempo = 2;
  620.  13       Rhythm = 40;
  621.  14       Path='.';
  622.  15       Painting = 'FRACTAL.DAT';
  623.  16       Framework = 'VALUES.DAT';
  624.  17 
  625.  18 const No_Error = $00;
  626.  19       Not_Found = $02;
  627.  20       Access_Denied = $05;
  628.  21 
  629.  22 const Read_Only = $00;
  630.  23       Write_Only = $01;
  631.  24       Read_Write = $02;
  632.  25       Deny_All = $10;
  633.  26       Deny_Write = $20;
  634.  27       Deny_Read = $30;
  635.  28       Deny_None = $40;
  636.  29 
  637.  30 type Count_Type = byte;
  638.  31      Size_Type = word;
  639.  32 
  640.  33 {$ifdef CPU87}
  641.  34      Real_Type = single;
  642.  35 {$else}
  643.  36      Real_Type = real;
  644.  37 {$endif}
  645.  38 
  646.  39 type Header = record
  647.  40                 Sound: boolean;
  648.  41                 AtV,
  649.  42                 ToV: Size_Type;
  650.  43               end;
  651.  44 
  652.  45 type Shape = record
  653.  46                Flux: Header;
  654.  47                H,
  655.  48                V: Size_Type;
  656.  49                Most: Count_Type;
  657.  50                BitPixel,
  658.  51                PixelByte: byte;
  659.  52                ByteLine: word;
  660.  53                Top,
  661.  54                Left,
  662.  55                YInc,
  663.  56                XInc: Real_Type;
  664.  57                Interlace: boolean;
  665.  58              end;
  666.  59 
  667.  60 var PriorExit: pointer;
  668.  61 
  669.  62 {$f+}
  670.  63 procedure Terminate;
  671.  64 {$f-}
  672.  65 
  673.  66 begin
  674.  67 CloseGraph;
  675.  68 ExitProc:=PriorExit;
  676.  69 end;
  677.  70 
  678.  71 const Colors = 3;
  679.  72 
  680.  73 procedure Initiate;
  681.  74 
  682.  75 const Mode: integer = CGAC0;
  683.  76       Device: integer= CGA;
  684.  77 
  685.  78 var Result: integer;
  686.  79 
  687.  80 begin
  688.  81 Result:=RegisterBGIdriver(@CGADriverProc);
  689.  82 InitGraph(Device, Mode, Path);
  690.  83 Result:=RegisterBGIfont(@GothicFontProc);
  691.  84 Result:=RegisterBGIfont(@TriplexFontProc);
  692.  85 Result:=RegisterBGIfont(@SmallFontProc);
  693.  86 PriorExit:=ExitProc;
  694.  87 ExitProc:=@Terminate;
  695.  88 end;
  696.  89 
  697.  90 procedure Inculcate;
  698.  91 
  699.  92 type ColorType = 1..Colors;
  700.  93 
  701.  94 var Hue: array[ColorType] of byte;
  702.  95 
  703.  96 procedure Adjust;
  704.  97 
  705.  98 const BackGround = 7;
  706.  99 
  707. 100 var Index,
  708. 101     Cycle: ColorType;
  709. 102     Group: array[ColorType] of byte;
  710. 103 
  711. 104 begin
  712. 105 Randomize;
  713. 106 SetBkColor(Random(Background));
  714. 107 for Cycle:=1 to Colors
  715. 108 do Group[Cycle]:=Cycle;
  716. 109 for Cycle:=Colors downto 1
  717. 110 do begin
  718. 111    Index:=Random(Cycle) + 1;
  719. 112    Hue[Cycle]:=Group[Index];
  720. 113    Move(Group[Index + 1], Group[Index], Colors - Index);
  721. 114    end;
  722. 115 end;
  723. 116 
  724. 117 const AtH = 159;
  725. 118       AtV = 66;
  726. 119       Offset = 40;
  727. 120       FontSize = 4;
  728. 121       TitleSize = 5;
  729. 122       NameSize = 1;
  730. 123 
  731. 124 type Axes = (X,Y);
  732. 125      Pair = array[Axes] of shortint;
  733. 126 
  734. 127 var Height,
  735. 128     Cycle: byte;
  736. 129 
  737. 130 const Credit: string = 'Mandelbrot Set';
  738. 131       Shift: array[1..8] of Pair = ((-1,-1),(0,-1),(1,1),
  739. 132                                     (-1,0),(1,0),
  740. 133                                     (-1,1),(0,1),(1,1));
  741. 134 
  742. 135 begin
  743. 136 Adjust;
  744. 137 SetColor(Hue[1]);
  745. 138 SetTextJustify(CenterText, CenterText);
  746. 139 SetTextStyle(GothicFont, HorizDir, TitleSize);
  747. 140 for Cycle:=1 to 8
  748. 141 do OutTextXY(AtH + Shift[Cycle][X], AtV + Shift[Cycle][Y], Credit);
  749. 142 SetColor(Hue[2]);
  750. 143 OutTextXY(AtH, AtV, Credit);
  751. 144 
  752. 145 SetColor(Hue[3]);
  753. 146 SetTextStyle(TriplexFont, HorizDir, FontSize);
  754. 147 OutTextXY(AtH, AtV - Offset, 'GWNet');
  755. 148 
  756. 149 SetTextStyle(DefaultFont, HorizDir, NameSize);
  757. 150 OutTextXY(AtH, AtV + Offset, 'The Mad Programmer strikes again!');
  758. 151 end;
  759. 152 
  760. 153 var Seed: Shape;
  761. 154 
  762. 155 procedure Anticipate;
  763. 156 
  764. 157 procedure Respond;
  765. 158 
  766. 159 const Escape = #27;
  767. 160 
  768. 161 var Key: char;
  769. 162 
  770. 163 begin
  771. 164 while Keypressed
  772. 165 do begin
  773. 166    Key:=ReadKey;
  774. 167    if Key=Escape
  775. 168    then Halt;
  776. 169    end;
  777. 170 end;
  778. 171 
  779. 172 type States = (Idle, Busy);
  780. 173 
  781. 174 procedure Report(Now: States);
  782. 175 
  783. 176 function NewHue: byte;
  784. 177 
  785. 178 const Hue: byte = 0;
  786. 179 
  787. 180 begin
  788. 181 if Hue=Colors
  789. 182 then Hue:=1
  790. 183 else Inc(Hue);
  791. 184 NewHue:=Hue;
  792. 185 end;
  793. 186 
  794. 187 const Off = 0;
  795. 188       Left = 0;
  796. 189       LowLine = 189;
  797. 190       FontSize = 4;
  798. 191 
  799. 192 type Note = string[10];
  800. 193 
  801. 194 const Message: array[States] of Note = ('waiting...',
  802. 195                                         'working...');
  803. 196 
  804. 197 begin
  805. 198 SetTextStyle(SmallFont, HorizDir, FontSize);
  806. 199 SetTextJustify(LeftText, TopText);
  807. 200 SetColor(Off);
  808. 201 OutTextXY(Left, LowLine, Message[Pred(Now)]);
  809. 202 SetColor(NewHue);
  810. 203 OutTextXY(Left, LowLine, Message[Now]);
  811. 204 end;
  812. 205 
  813. 206 const Time = 500;
  814. 207 
  815. 208 var Notice: file of Shape;
  816. 209 
  817. 210 begin
  818. 211 Report(Idle);
  819. 212 Assign(Notice, Framework);
  820. 213 FileMode:= Read_Write + Deny_None;
  821. 214 repeat
  822. 215   Respond;
  823. 216   Delay(Time);
  824. 217   {$i-}
  825. 218   Reset(Notice);
  826. 219   {$i+}
  827. 220 until (IOResult = No_Error);
  828. 221 Read(Notice, Seed);
  829. 222 Close(Notice);
  830. 223 Report(Busy);
  831. 224 end;
  832. 225 
  833. 226 procedure Cultivate;
  834. 227 
  835. 228 var Once: boolean;
  836. 229     Eye: file of Header;
  837. 230 
  838. 231 function Work: boolean;
  839. 232 
  840. 233 const Front = 0;
  841. 234 
  842. 235 begin
  843. 236 FileMode:=Read_Write + Deny_All;
  844. 237 repeat
  845. 238   {$i-}
  846. 239   Reset(Eye);
  847. 240   {$i+}
  848. 241 until (IOResult = No_Error);
  849. 242 Read(Eye, Seed.Flux);
  850. 243 Work:=false;
  851. 244 with Seed
  852. 245 do begin
  853. 246    if Once
  854. 247    then Dec(Flux.ToV);
  855. 248    if Flux.ToV = 0
  856. 249    then begin
  857. 250         Close(Eye);
  858. 251         repeat
  859. 252           Erase(Eye);
  860. 253         until (IOResult = No_Error);
  861. 254         end
  862. 255    else begin
  863. 256         if Flux.AtV > 0
  864. 257         then begin
  865. 258              Dec(Flux.AtV);
  866. 259              Work:=true;
  867. 260              end;
  868. 261         Seek(Eye, Front);
  869. 262         Write(Eye, Flux);
  870. 263         Close(Eye);
  871. 264         end;
  872. 265    end;
  873. 266 end;
  874. 267 
  875. 268 type Pixels = array[byte] of byte;
  876. 269      Count_Array = array[byte] of Count_Type;
  877. 270 
  878. 271 var Span,
  879. 272     Base,
  880. 273     Scale,
  881. 274     Middle: word;
  882. 275     Map: real;
  883. 276     Innate: ^Pixels;
  884. 277     Zone: ^Count_Array;
  885. 278     Canvas: file;
  886. 279 
  887. 280 procedure Prepare;
  888. 281 
  889. 282 var Range: word;
  890. 283 
  891. 284 const Height = 200;
  892. 285 
  893. 286 begin
  894. 287 Assign(Eye, Framework);
  895. 288 Assign(Canvas, Painting);
  896. 289 with Seed
  897. 290 do begin
  898. 291    Middle:=V div 2;
  899. 292    Map:=Height / V;
  900. 293    Range:=(Treble - Bass) div Choir;
  901. 294    Scale:=Range div Most;
  902. 295    Base:=Bass + Range * Random(Choir);
  903. 296    Span:=SizeOf(Count_Type) * H;
  904. 297    GetMem(Zone, Span);
  905. 298    GetMem(Innate, ByteLine);
  906. 299    FileMode:=Write_Only + Deny_None;
  907. 300    Reset(Canvas, ByteLine);
  908. 301    end;
  909. 302 SetWriteMode(XORPut);
  910. 303 SetColor(Random(Colors) + 1);
  911. 304 end;
  912. 305 
  913. 306 procedure Conclude;
  914. 307 
  915. 308 begin
  916. 309 Close(Canvas);
  917. 310 FreeMem(Zone, Span);
  918. 311 FreeMem(Innate, Seed.ByteLine);
  919. 312 SetWriteMode(NormalPut);
  920. 313 ClearDevice;
  921. 314 end;
  922. 315 
  923. 316 procedure Abandon;
  924. 317 
  925. 318 var Key: char;
  926. 319 
  927. 320 begin
  928. 321 NoSound;
  929. 322 Conclude;
  930. 323 while KeyPressed
  931. 324 do Key:=ReadKey;
  932. 325 Halt;
  933. 326 end;
  934. 327 
  935. 328 procedure Develop;
  936. 329 
  937. 330 procedure Convert;
  938. 331 
  939. 332 var Merge,
  940. 333     Inner: byte;
  941. 334     Cycle: word;
  942. 335     Index: Size_Type;
  943. 336 
  944. 337 begin
  945. 338 Cycle:=0;
  946. 339 Index:=Seed.H;
  947. 340 with Seed
  948. 341 do repeat
  949. 342      for Inner:=1 to PixelByte
  950. 343      do begin
  951. 344         Merge:=Merge shl BitPixel or (Most - Zone^[Index]);
  952. 345         Dec(Index);
  953. 346         end;
  954. 347      Innate^[Cycle]:=Merge;
  955. 348      Inc(Cycle);
  956. 349    until Cycle=ByteLine;
  957. 350 end;
  958. 351 
  959. 352 procedure Gauge;
  960. 353 
  961. 354 const Left= 0;
  962. 355       Right= 319;
  963. 356 
  964. 357 const Fore: word = 0;
  965. 358       Rear: word = 0;
  966. 359       PreFore: word = 0;
  967. 360       PreRear: word = 0;
  968. 361 
  969. 362 begin
  970. 363 with Seed.Flux
  971. 364 do begin
  972. 365    if Once
  973. 366    then Rectangle(Left, PreFore, Right, PreRear);
  974. 367    Fore:=Trunc(AtV * Map);
  975. 368    Rear:=Trunc(ToV * Map);
  976. 369    end;
  977. 370 Rectangle(Left, Fore, Right, Rear);
  978. 371 PreFore:=Fore;
  979. 372 PreRear:=Rear;
  980. 373 end;
  981. 374 
  982. 375 var Offset: word;
  983. 376 
  984. 377 const Single = 1;
  985. 378 
  986. 379 begin
  987. 380 Convert;
  988. 381 with Seed
  989. 382 do if Interlace
  990. 383    then begin
  991. 384         Offset:=Flux.AtV div 2;
  992. 385         if Odd(Flux.AtV)
  993. 386         then Seek(Canvas, Middle + Offset)
  994. 387         else Seek(Canvas, Offset)
  995. 388         end
  996. 389    else Seek(Canvas, Flux.AtV);
  997. 390 BlockWrite(Canvas, Innate^, Single);
  998. 391 Gauge;
  999. 392 end;
  1000. 393 
  1001. 394 var ZR,
  1002. 395     ZI,
  1003. 396     ZR2,
  1004. 397     ZI2: Real_Type;
  1005. 398 
  1006. 399 function Chaotic:boolean;
  1007. 400 
  1008. 401 begin
  1009. 402 ZR2:=ZR * ZR;
  1010. 403 ZI2:=ZI * ZI;
  1011. 404 Chaotic:=(ZR2 + ZI2 < 4);
  1012. 405 end;
  1013. 406 
  1014. 407 var I: Count_Type;
  1015. 408 
  1016. 409 function Note: word;
  1017. 410 
  1018. 411 begin
  1019. 412 Note:=Trunc(Base + I * Scale);
  1020. 413 end;
  1021. 414 
  1022. 415 procedure Sing;
  1023. 416 
  1024. 417 const Cycle: word = 0;
  1025. 418       Duration: word = 0;
  1026. 419 
  1027. 420 begin
  1028. 421 Inc(Cycle);
  1029. 422 if Cycle=Rhythm
  1030. 423 then begin
  1031. 424      Cycle:=0;
  1032. 425      Duration:=(Rhythm shr Tempo) shl Random(Tempo);
  1033. 426      Sound(Note);
  1034. 427      end;
  1035. 428 if Cycle = Duration
  1036. 429 then NoSound;
  1037. 430 end;
  1038. 431 
  1039. 432 var X: Size_Type;
  1040. 433     CR,
  1041. 434     CI: Real_Type;
  1042. 435 
  1043. 436 begin
  1044. 437 Prepare;
  1045. 438 Once:=false;
  1046. 439 while Work
  1047. 440 do with Seed
  1048. 441    do begin
  1049. 442       X:=H;
  1050. 443       CR:=Left;
  1051. 444       CI:=Top - (Flux.AtV * YInc);
  1052. 445       repeat
  1053. 446          ZR:=CR;
  1054. 447          ZI:=CI;
  1055. 448          I:=1;
  1056. 449          while Chaotic and (I < Most)
  1057. 450          do begin
  1058. 451             ZR:=ZR2 - ZI2 + CR;
  1059. 452             ZI:=2 * ZR * ZI + CI;
  1060. 453             Inc(I);
  1061. 454             end;
  1062. 455          Dec(X);
  1063. 456          Zone^[X]:=I;
  1064. 457          CR:=CR + XInc;
  1065. 458          if Flux.Sound
  1066. 459          then Sing;
  1067. 460       until (X=0);
  1068. 461       Develop;
  1069. 462       if KeyPressed
  1070. 463       then Abandon;
  1071. 464       Once:=true;
  1072. 465       end;
  1073. 466 Conclude;
  1074. 467 end;
  1075. 468 
  1076. 469 const EndOfTime = false;
  1077. 470 
  1078. 471 begin
  1079. 472 Initiate;
  1080. 473 repeat
  1081. 474   Inculcate;
  1082. 475   Anticipate;
  1083. 476   Cultivate;
  1084. 477 until EndOfTime;
  1085. 478 {Terminate;}
  1086. 479 end.
  1087.  
  1088.                                    Comments
  1089.  
  1090. Lines 15 - 31 mirror the same values in LEADER as do lines 39 - 58.
  1091.  
  1092. Lines 33 - 37 give an example of the use of the CPU87 conditional directive to
  1093. globally change real number types.  Likewise, lines 1 - 3 enable 8087
  1094. emulation.  In this state they may possibly conflict with the LEADER;
  1095. Real_Type must match in both programs.
  1096.  
  1097. The Terminate procedure is defined in Far mode because it is defined as the new
  1098. ExitProc.
  1099.  
  1100. Lines 71 - 151 display a title screen and initialize the new error exit
  1101. procedure.
  1102.  
  1103. Lines 153 - 224 form the Anticipate procedure which waits for the signal from
  1104. the LEADER.  It allows the program to be aborted with the Escape key in the
  1105. wait for the LEADER (in the Respond procedure, lines 157 - 170).  Lines 172 -
  1106. 204 Report on the status of the FOLLOWER.  Lines 206 - 224 monitor the current
  1107. directory for the VALUES.DAT file.  If it exists it is read into the Seed
  1108. variable (line 221) in Read_Write and Deny_None mode; this effectively allows
  1109. many (but not always all, see line 220) FOLLOWERs to read this file
  1110. simultaneously prior to processing with no sharing conflict (actually Read_Only
  1111. is all that is necessary).
  1112.  
  1113. Lines 226 - 467 form the major procedure Cultivate that comprises the main loop
  1114. to process lines.
  1115.  
  1116. Lines 438 - 465 hold the main line processing loop along with the Mandelbrot
  1117. algorithm.  It calls on various subroutines:
  1118.  
  1119. The subroutine Prepare (280 - 304) sets up variables.  The dynamically
  1120. allocated heap variable Zone contains one line of Count_Type variables, and
  1121. Innate contains the corresponding line of raw graphics data.  It also OPENs the
  1122. Canvas untyped file variable to the raw graphics data in Write_Only +
  1123. Deny_None.  There are never any sharing conflicts with this file because all
  1124. data write operations are guaranteed not to overlap.
  1125.  
  1126. The function Work gets the status of the parallel processing.  If the FOLLOWER
  1127. is the last to finish this routine deletes the auxiliary file (at line 252; it
  1128. may have to repeat the operation because it can conflict with the monitoring by
  1129. the LEADER) and returns false, otherwise it loads the Seed.Flux record (the
  1130. section of the auxiliary file that changes) with current unprocessed line
  1131. number, updates the auxiliary file, and returns true.  Note that the auxiliary
  1132. file is opened in Read_Write (for the monitor and update) and Deny_All (to
  1133. guarantee synchronization).
  1134.  
  1135. The procedure Develop (line 461) converts the Zone array to Innate form, writes
  1136. the completed line to the graphics file at lines 379 - 392 (taking care of
  1137. interlacing), and gives a visual cue of processing progress (in Gauge, lines
  1138. 352 - 373).
  1139.  
  1140. The procedure Conclude is designed as the twin of Prepare to handle proper
  1141. termination procedure.  It closes the raw graphics file Canvas (line 309),
  1142. deallocates heap variables (lines 310 and 311) and resets graphics defaults
  1143. (the WriteMode set by Prepare at 302 for Report at line 201 and Gauge at 370,
  1144. and clears the screen at line 313).
  1145.  
  1146.                                      Notes
  1147.  
  1148. Note that LEADER and FOLLOWER must be executed in the same directory and each
  1149. granted appropriate rights (Read, Write, Create, Delete, Search).
  1150.  
  1151. LEADER uses the link module Drivers defined by TP that contains all BGI
  1152. graphics drivers.  Consult the manual for instructions on creating it.  It can
  1153. contain all drivers but ideally contains only the one defined by GraphDriver. 
  1154. FOLLOWER uses the link module Fonts in addition, the same notes apply.
  1155.  
  1156. LEADER and FOLLOWER have a new and additional approach to visual in conveying
  1157. fractal results.  A few lines in LEADER and many in FOLLOWER are dedicated to
  1158. the process of broadcasting values in SOUND!  The LEADER has the capability to
  1159. turn sound on and off dynamically (note the Sound variable located in the
  1160. dynamic part of the auxiliary file, line 40).  There are many values that
  1161. change this operation (notably those at the beginning of FOLLOWER in lines 9 -
  1162. 13) that require some adjustment for a symphony instead of cacophony
  1163. (particularly because of varying processor speeds).
  1164.  
  1165. What about "fault tolerance"?  An unprocessed line results in the display when
  1166. any FOLLOWERs are prevented from terminating properly.  They can be interrupted
  1167. at the end of processing a line with no effect on the whole (except a slower
  1168. completion time), note the Abandon procedure in FOLLOWER called at line 463
  1169. for this purpose.  Any larger degree of tolerance would have to sacrifice the
  1170. compact size and form of the auxiliary file.  For example, this file could
  1171. contain an array of boolean variables that represent the status of every line;
  1172. under this scheme an operation is possible where FOLLOWERs could "abscond" at
  1173. any time (lose power, be rebooted, etc.) with no effect on the result.
  1174.  
  1175. In FOLLOWER the procedure/variable/stack nesting gets fairly deep in the
  1176. Cultivate procedure.  This is certainly costly in terms of execution time due
  1177. to the multiple levels of indirection required to access variables.  Also, the
  1178. Chaotic function is concise and convenient from a syntactical standpoint but is
  1179. costly as well because it represents call overhead in the crucial main loop. 
  1180. In both programs efficiency was compromised for form.
  1181.